//
//  LocationService.m
//  YuanXinBaiduMap
//
//  Created by 晏德智 on 16/9/26.
//  Copyright © 2016年 晏德智. All rights reserved.
//

#import "BaiduLocationKitService.h"
#import <BMKLocationkit/BMKLocationComponent.h>

@interface BaiduLocationKitService () <BMKLocationManagerDelegate>

// 单次定位回调
@property(nonatomic, copy) BMKLocatingCompletionBlock completionBlock;

@end

@implementation BaiduLocationKitService
{
    BMKLocationManager *_locationManager;
    BMKLocationManager *_singleLocationManager;
    BMKLocation * _currentLocation;
    CLLocationDegrees _headingDirection;
    NSDictionary<NSString *, id> *_lastLocationEvent;
    BaiduLocationOptions _observerOptions;
}

- (void)dealloc
{
    if (_locationManager) {
        [_locationManager stopUpdatingLocation];
    }
    if (_singleLocationManager) {
        [_singleLocationManager stopUpdatingLocation];
    }
    _locationManager.delegate = nil;
    _locationManager = nil;
    _singleLocationManager.delegate = nil;
    _singleLocationManager = nil;
    _completionBlock = nil;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        //[self initBlock];
        [self initLocation];
        [self initSingleLocation];
    }
    return self;
}

+ (void)requestLocationAuthorization:(void (^)(BOOL))completeHandler {
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    if (!appName)appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleName"];
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:[NSString stringWithFormat:@"请在iPhone的设置-隐私->允许%@使用你的定位",appName] preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        if ([UIDevice currentDevice].systemVersion.floatValue > 10.0) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
        } else if ([UIDevice currentDevice].systemVersion.floatValue > 8.0) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        } else {
            // 私有API上线会被拒
            //[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy&path=LOCATION_SERVICES"]];
        }
#pragma clang diagnostic pop
        if (completeHandler) {
            completeHandler(YES);
        }
    }];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        if (completeHandler) {
            completeHandler(NO);
        }
    }];
    [alertController addAction:sureAction];
    [alertController addAction:cancelAction];
    UIViewController *presentedController = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController?:[UIApplication sharedApplication].keyWindow.rootViewController;
    [presentedController presentViewController:alertController animated:YES completion:nil];
}

#pragma mark - Private API

-(void)initLocation
{
    //初始化实例
    _locationManager = [[BMKLocationManager alloc] init];
    //设置delegate
    _locationManager.delegate = self;
    //设置返回位置的坐标系类型
    _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;
    //设置距离过滤参数
    _locationManager.distanceFilter = kCLDistanceFilterNone;
    //设置预期精度参数
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    //设置应用位置类型
    _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    //设置是否自动停止位置更新
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    //设置是否允许后台定位
    //_locationManager.allowsBackgroundLocationUpdates = YES;
    //设置位置获取超时时间
    _locationManager.locationTimeout = 10;
    //设置获取地址信息超时时间
    _locationManager.reGeocodeTimeout = 10;
    
}

-(void)initSingleLocation
{
    //初始化实例
    _singleLocationManager = [[BMKLocationManager alloc] init];
    //设置delegate
    _singleLocationManager.delegate = self;
    //设置返回位置的坐标系类型
    _singleLocationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;
    //设置距离过滤参数
    _singleLocationManager.distanceFilter = kCLDistanceFilterNone;
    //设置预期精度参数
    _singleLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
    //设置应用位置类型
    _singleLocationManager.activityType = CLActivityTypeAutomotiveNavigation;
    //设置是否自动停止位置更新
    _singleLocationManager.pausesLocationUpdatesAutomatically = NO;
    //设置是否允许后台定位
    //_singleLocationManager.allowsBackgroundLocationUpdates = YES;
    //设置位置获取超时时间
    _singleLocationManager.locationTimeout = 10;
    //设置获取地址信息超时时间
    _singleLocationManager.reGeocodeTimeout = 10;
    
}

-(void)initBlock
{
    __weak typeof (self) weakSelf = self;
    self.completionBlock = ^(BMKLocation *location, BMKLocationNetworkState state, NSError *error)
    {
        if (error)
        {
            NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
        }
        
        if (location.location) {//得到定位信息，添加annotation
            NSLog(@"LOC = %@",location.location);
        }
        
        if (location.rgcData) {
            NSLog(@"rgc = %@",[location.rgcData description]);
        }
        
        NSLog(@"netstate = %d",state);
    };
}

- (void)getCurrentPositionWithOptions:(BaiduLocationOptions)options completion:(BMKLocatingCompletionBlock)completionBlock
{
    _singleLocationManager.distanceFilter = options.distanceFilter;
    _singleLocationManager.desiredAccuracy = options.accuracy;
    // 请求一次定位。您可以选择在一次定位时是否返回地址信息（需要联网）。
    // 是否带有逆地理信息(获取逆地理信息需要联网)
    BOOL _isNeedAddr = YES;
    // 是否带有移动热点识别状态(需要联网)
    BOOL _isNeedHotSpot = NO;
    //[_singleLocationManager requestLocationWithReGeocode:_isNeedAddr withNetworkState:_isNeedHotSpot completionBlock:self.completionBlock];
    [_singleLocationManager requestLocationWithReGeocode:_isNeedAddr withNetworkState:_isNeedHotSpot completionBlock:completionBlock];
}

#pragma mark - Public API

/**
 *打开定位服务
 *需要在info.plist文件中添加(以下二选一，两个都添加默认使用NSLocationWhenInUseUsageDescription)：
 *NSLocationWhenInUseUsageDescription 允许在前台使用时获取GPS的描述
 *NSLocationAlwaysUsageDescription 允许永远可获取GPS的描述
 */
-(void)startUserLocationService {
    // 开启持续定位
    // 如果需要持续定位返回地址信息（需要联网），请设置如下：
    [_locationManager setLocatingWithReGeocode:YES];
    [_locationManager startUpdatingLocation];
    if (self.enableHeadingUpdates && BMKLocationManager.headingAvailable) {
        [_locationManager startUpdatingHeading];
    }
}
/**
 *关闭定位服务
 */
- (void)stopUserLocationService {
    [_locationManager stopUpdatingLocation];
    [_locationManager stopUpdatingHeading];
}

#pragma mark - 定位参数，具体含义可参考CLLocationManager相关属性的注释

/// 设定定位的最小更新距离。默认为kCLDistanceFilterNone
- (void)setDistanceFilter:(CLLocationDistance)distanceFilter
{
    _locationManager.distanceFilter = distanceFilter;
}

/// 设定定位精度。默认为kCLLocationAccuracyBest。
- (void)setDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy
{
    _locationManager.desiredAccuracy = desiredAccuracy;
}

/// 指定定位是否会被系统自动暂停。默认为YES。只在iOS 6.0之后起作用。
- (void)setPausesLocationUpdatesAutomatically:(BOOL)pausesLocationUpdatesAutomatically
{
    _locationManager.pausesLocationUpdatesAutomatically = pausesLocationUpdatesAutomatically;
}

///指定定位：是否允许后台定位更新。默认为NO。只在iOS 9.0之后起作用。设为YES时，Info.plist中 UIBackgroundModes 必须包含 "location"
- (void)setAllowsBackgroundLocationUpdates:(BOOL)allowsBackgroundLocationUpdates
{
    _locationManager.allowsBackgroundLocationUpdates = allowsBackgroundLocationUpdates;
}

#pragma mark - BMKLocationManagerDelegate

/**
 *  @brief 当定位发生错误时，会调用代理的此方法。
 *  @param manager 定位 BMKLocationManager 类。
 *  @param error 返回的错误，参考 CLError 。
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error
{
    if ([manager isEqual:_singleLocationManager]) {
        return;
    }
    if (self.didUpdateLocation) {
        self.didUpdateLocation(nil, error);
    }
}

/**
 *  @brief 连续定位回调函数。
 *  @param manager 定位 BMKLocationManager 类。
 *  @param location 定位结果，参考BMKLocation。
 *  @param error 错误信息。
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didUpdateLocation:(BMKLocation * _Nullable)location orError:(NSError * _Nullable)error
{
    if ([manager isEqual:_singleLocationManager]) {
        return;
    }
    _currentLocation = location;
    if (self.didUpdateLocation) {
        self.didUpdateLocation(location, error);
    }
}

/**
 *  @brief 定位权限状态改变时回调函数
 *  @param manager 定位 BMKLocationManager 类。
 *  @param status 定位权限状态。
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    
}

/**
 * @brief 该方法为BMKLocationManager提示需要设备校正回调方法。
 * @param manager 提供该定位结果的BMKLocationManager类的实例。
 */
- (BOOL)BMKLocationManagerShouldDisplayHeadingCalibration:(BMKLocationManager * _Nonnull)manager
{
    return YES;
}

/**
 * @brief 该方法为BMKLocationManager提供设备朝向的回调方法。
 * @param manager 提供该定位结果的BMKLocationManager类的实例
 * @param heading 设备的朝向结果
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager
          didUpdateHeading:(CLHeading * _Nullable)heading
{
    if ([manager isEqual:_singleLocationManager]) {
        return;
    }
    CLLocationDegrees headingDelta = fabs(_headingDirection - heading.trueHeading);
    BOOL update = self.headingFilter == kCLHeadingFilterNone; // 为避免卡死，不建议任何移动都回调，所以这个不作为参考
    update = headingDelta > MAX(15, self.headingFilter); // 以此为准
    if (update) {
        _headingDirection = heading.trueHeading;
        if (self.didUpdateHeading) {
            self.didUpdateHeading(_currentLocation, heading, nil);
        }
    }
}

/**
 * @brief 该方法为BMKLocationManager所在App系统网络状态改变的回调事件。
 * @param manager 提供该定位结果的BMKLocationManager类的实例
 * @param state 当前网络状态
 * @param error 错误信息
 */
- (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager
     didUpdateNetworkState:(BMKLocationNetworkState)state orError:(NSError * _Nullable)error
{
    
}

@end
